package com.yjd.bi.etl.user.service;

import com.yjd.bi.cashout.model.CashDcsOrderModel;
import com.yjd.bi.cashout.service.ICashDcsOrderService;
import com.yjd.bi.etl.comm.BaseService;
import com.yjd.bi.growing.model.UserGrowingStatisticsModel;
import com.yjd.bi.growing.service.IUserGrowingStatisticsService;
import com.yjd.bi.user.dto.UserBaseInfoDto;
import com.yjd.bi.user.dto.UserRemainDto;
import com.yjd.bi.user.dto.UserTicketUsedDto;
import com.yjd.bi.user.enums.*;
import com.yjd.bi.growing.ntx.IUserGrowingStatisticsServiceNtx;
import com.yjd.bi.user.model.UserModel;
import com.yjd.bi.user.service.IUserService;
import com.yjd.comm.annotation.ServiceRemoteProxy;
import com.yjd.comm.base.enums.DbWREnums;
import com.yjd.comm.enums.UserEnums;
import com.yjd.comm.rpm.RpmServiceKeyEnum;
import com.yjd.comm.util.FrameUtil;
import com.yjd.comm.util.ThreadUtil;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.concurrent.*;

@Component("userGrowingStatisticsService")
public class UserGrowingStatisticsService extends BaseService {

  @ServiceRemoteProxy(serviceUrlResouceKey = RpmServiceKeyEnum.RPM_BI_SERVICE_KEY)
  private IUserGrowingStatisticsService userGrowingStatisticsService;

  @ServiceRemoteProxy(serviceUrlResouceKey = RpmServiceKeyEnum.RPM_BI_SERVICE_KEY)
  private IUserService userService;

  @ServiceRemoteProxy(serviceUrlResouceKey = RpmServiceKeyEnum.RPM_BI_SERVICE_KEY)
  private IUserGrowingStatisticsServiceNtx nTxUserGrowingStatisticsService;

  @ServiceRemoteProxy(serviceUrlResouceKey = RpmServiceKeyEnum.RPM_BI_SERVICE_KEY)
  private ICashDcsOrderService cashDcsOrderService;

  private static final int batchSize = 50;

  private static long INTERVAL_1DAY_SECONDS = 86400L; //1天的时间间隔
  private static long INTERVAL_30DAY_SECONDS = 2592000L; //30天的时间间隔
  private static long INTERVAL_60DAY_SECONDS = 5184000L; //60天的时间间隔
  private static long INTERVAL_90DAY_SECONDS = 7776000L; //90天的时间间隔

  private static long TIME_STAMP_20170101 = 1483200000L; //2017年1月1日

  public void execute() throws Exception {

    /**
     * 循环处理所有user数据
     * 每批处理batchSize条数据
     * com.yjd.bi.growing.ntx.IUserGrowingStatisticsServiceNtx#insert 是无事物的，创建成功后就提交数据库
     * 先创建UserGrowingStatisticsModel，保证记录存在，使后面所有统计都是更新操作
     */
    int batch = 1;
    long userCount = userService.getModelListCount(FrameUtil.newHashMap(), DbWREnums.READ);
    while (userCount > 0) {
      processUserData(batch);
      userCount = userCount - batchSize;
      batch++;
    }

  }

  private void processUserData(int batch) throws Exception {
    final List<UserModel> users = userService.getModelList(FrameUtil.newHashMap(), (batch-1)*batchSize, batchSize, DbWREnums.READ);
    if(users == null || users.size() == 0){
      return; // 没有需要处理的数据
    }
    logger.info(String.format("用户成长数据统计：开始处理，batch：%s，data records：%s", batch, users.size()));

    for(UserModel user : users){
      UserGrowingStatisticsModel ugsm = userGrowingStatisticsService.getModelById(user.getUser_id(), DbWREnums.READ);
      if(ugsm == null){
        ugsm = new UserGrowingStatisticsModel();
        ugsm.setUser_id(user.getUser_id());
        ugsm.setRegist_time(user.getRegdate());
        ugsm.setRegist_channel(user.getChannel());
        ugsm.setCreate_time(FrameUtil.getTime());
        ugsm.setUpdate_time(ugsm.getCreate_time());
        ugsm = nTxUserGrowingStatisticsService.insert(ugsm);
      }

      final long user_id = user.getUser_id();

      // 用户基本信息
      submitTask(ThreadUtil.getThreadPoolTaskExecutor(), new Runnable() {
        @Override
        public void run() {
          long start = System.currentTimeMillis();
          try {
            baseInfo(user_id);
          } catch (Exception e) {
            logger.error("统计用户基本信息失败", e);
          }
          logger.info(user_id+"用户基本信息统计，cost(ms):"+(System.currentTimeMillis()-start));
        }
      });

      // 转化监控 (用户基本信息统计中已经记录)

      // 留存监控数据
      submitTask(ThreadUtil.getThreadPoolTaskExecutor(), new Runnable() {
        @Override
        public void run() {
          long start = System.currentTimeMillis();
          try {
            recordRemain(user_id);
          } catch (Exception e) {
            logger.error("统计留存监控数据失败", e);
          }
          logger.info(user_id+"留存监控数据统计，cost(ms):"+(System.currentTimeMillis()-start));
        }
      });

      //推广监控(用户留存统计中已经记录)

      // 流失监控数据
      submitTask(ThreadUtil.getThreadPoolTaskExecutor(), new Runnable() {
        @Override
        public void run() {
          long start = System.currentTimeMillis();
          try {
            recordLoss(user_id);
          } catch (Exception e) {
            logger.error("统计流失监控数据失败", e);
          }
          logger.info(user_id+"流失监控数据统计，cost(ms):"+(System.currentTimeMillis()-start));
        }
      });
    }
  }

  /**
   * 向线程池中添加任务
   * 如果失败，则不添加，暂停一段时间再添加
   * @param task
   */
  private void submitTask(ThreadPoolExecutor pool, Runnable task){
    try{
      pool.submit(task);
    }catch (RejectedExecutionException e){
      logger.warn("任务队列已满，等待5s");
      try {
        TimeUnit.SECONDS.sleep(5);
        submitTask(pool, task); // 再次添加未成功的任务
      } catch (InterruptedException e1) {
        // don't worries.
      }
    }
  }

  private void baseInfo(long user_id) throws Exception {
    UserBaseInfoDto baseInfoDto = userService.queryUserInfoById(user_id);
    if(baseInfoDto != null && baseInfoDto.getUser_id() != null){

      UserGrowingStatisticsModel model = new UserGrowingStatisticsModel();
      model.setUser_id(user_id);
      model.setUsername(baseInfoDto.getUsername() == null ? "" : baseInfoDto.getUsername());

      baseInfoDto.setBank_depo(baseInfoDto.getBank_depo() == null ? 0:baseInfoDto.getBank_depo());
      baseInfoDto.setUser_role(baseInfoDto.getUser_role() == null ? 0:baseInfoDto.getUser_role());

      model.setOpen_account(baseInfoDto.getOpen_account() ==null?0:baseInfoDto.getOpen_account());
      model.setAll_invest_amount(baseInfoDto.getAll_invest_amount()==null?0:baseInfoDto.getAll_invest_amount());
      model.setBalance(baseInfoDto.getAvailable() == null ? 0.0 : baseInfoDto.getAvailable());
      model.setUpdate_time(FrameUtil.getTime());
      model.setLatest_payback_time(baseInfoDto.getLatest_payback_time()==null?0:baseInfoDto.getLatest_payback_time());
      model.setCreditor_count(baseInfoDto.getCreditor_count() ==null?0:baseInfoDto.getCreditor_count());
      model.setFirst_recharge(baseInfoDto.getFirst_recharge()==null?0:baseInfoDto.getFirst_recharge());
      model.setFirst_invest(baseInfoDto.getFirst_invest()==null?0:baseInfoDto.getFirst_invest());
      model.setFirst_invest_amount(baseInfoDto.getFirst_invest_amount()==null?0:baseInfoDto.getFirst_invest_amount());
      model.setRegist_channel(baseInfoDto.getChannel()==null?0:baseInfoDto.getChannel());

      // 用户属性
      model.setUser_property(UserProperty.NORMAL_USER.getCode());
      if(baseInfoDto.getBank_depo().intValue() == 1){
        model.setUser_property(UserProperty.BANK_DEPO_USER.getCode());
      }
      if(UserEnums.UserType.isDz(baseInfoDto.getUser_type())){
        model.setUser_property(UserProperty.DZ_USER.getCode());
      }
      if(baseInfoDto.getUser_role().intValue() == 2){
        model.setUser_property(UserProperty.BORROW_USER.getCode());
      }

      // 用户状态
      model.setUser_status(UserStatus.REGISTER.getCode());
      if( model.getOpen_account().longValue() > 0 &&
        model.getFirst_recharge().longValue() == 0
        ){
        model.setUser_status(UserStatus.OPEN_ACCOUNT.getCode());
        model.setTransfer_status(TransferStatus.OPEN_ACCOUNT.getCode());
      }
      if (model.getOpen_account().longValue() == 0){
        model.setTransfer_status(TransferStatus.REGISTER.getCode());
      }
      if(model.getFirst_recharge() > 0 &&
        model.getFirst_invest().intValue() == 0){
        model.setUser_status(UserStatus.RECHARGED.getCode());
        model.setTransfer_status(TransferStatus.RECHARGED.getCode());
      }

      model.setUser_level(baseInfoDto.getUser_level_id());

      //6.流失状态(仅针对有过投资行为的用户)
      model.setAvailable_status(AvailableStatus.AVAILABLE.getCode());
      if (model.getAll_invest_amount() > 0) {
        if (model.getCreditor_count() == 0
                && ((FrameUtil.getTime()- model.getLatest_payback_time() > INTERVAL_60DAY_SECONDS))){
          model.setAvailable_status(AvailableStatus.UNAVAILABLE.getCode());//已流失：无在投项目且最后回款在60天以上
        }
        if (model.getCreditor_count() == 1
                && (FrameUtil.getTime()- model.getLatest_payback_time() >= -INTERVAL_30DAY_SECONDS)){
          model.setAvailable_status(AvailableStatus.WILL_UNAVAILABLE.getCode());//存在流失倾向：在投项目=1且最后一次回款时间<=30天
        }
      }

      userGrowingStatisticsService.update(model);
    }
  }

  private void transferInfo(long user_id) throws Exception {
    UserGrowingStatisticsModel model = new UserGrowingStatisticsModel();
    model.setUser_id(user_id);

    userGrowingStatisticsService.update(model);
  }
  /**
   * 留存监控和推广监控
   */
  private void recordRemain(long user_id) throws Exception {

    UserRemainDto remainDto = userService.queryUserRemainInfoById(user_id);
    if (remainDto != null) {
      UserGrowingStatisticsModel model = new UserGrowingStatisticsModel();
      model.setUser_id(user_id);
      //1.购买出借项目次数
      model.setInvest_times(remainDto.getInvest_times() == null ? 0 : remainDto.getInvest_times());
      //2.购买债权项目次数
      model.setInvest_creditor_times(remainDto.getInvest_creditor_times() == null ? 0 : remainDto.getInvest_creditor_times());
      //累计投资次数(购买出借项目次数+购买债权项目次数)
      model.setAll_invest_times(model.getInvest_times() + model.getInvest_creditor_times());
      //3.债权转让次数
      model.setCreditor_transfer_times(remainDto.getCreditor_transfer_times() == null ? 0 : remainDto.getCreditor_transfer_times());
      //4.30天内购买出借项目次数
      model.setInvest_times_30d(remainDto.getInvest_times_30d() == null ? 0 : remainDto.getInvest_times_30d());
      //5.60天内购买出借项目次数
      model.setInvest_times_60d(remainDto.getInvest_times_60d() == null ? 0 : remainDto.getInvest_times_60d());
      //6.90天内购买出借项目次数
      model.setInvest_times_90d(remainDto.getInvest_times_90d() == null ? 0 : remainDto.getInvest_times_90d());
      //7.30天内购买出借项目金额
      model.setInvest_amount_30d(remainDto.getInvest_amount_30d() == null ? 0.00 : remainDto.getInvest_amount_30d());
      //8.60天内购买出借项目金额
      model.setInvest_amount_60d(remainDto.getInvest_amount_60d() == null ? 0.00 : remainDto.getInvest_amount_60d());
      //9.90天内购买出借项目金额
      model.setInvest_amount_90d(remainDto.getInvest_amount_90d() == null ? 0.00 : remainDto.getInvest_amount_90d());
      //10.30天内购买债权项目次数
      model.setInvest_creditor_times_30d(remainDto.getInvest_creditor_times_30d() == null ? 0 : remainDto.getInvest_creditor_times_30d());
      //11.60天内购买债权项目次数
      model.setInvest_creditor_times_60d(remainDto.getInvest_creditor_times_60d() == null ? 0 : remainDto.getInvest_creditor_times_60d());
      //12.90天内购买债权项目次数
      model.setInvest_creditor_times_90d(remainDto.getInvest_creditor_times_90d() == null ? 0 : remainDto.getInvest_creditor_times_90d());
      //13.30天内购买债权项目金额
      model.setInvest_creditor_amount_30d(remainDto.getInvest_creditor_amount_30d() == null ? 0.00 : remainDto.getInvest_creditor_amount_30d());
      //14.60天内购买债权项目金额
      model.setInvest_creditor_amount_60d(remainDto.getInvest_creditor_amount_60d() == null ? 0.00 : remainDto.getInvest_creditor_amount_60d());
      //15.90天内购买债权项目金额
      model.setInvest_creditor_amount_90d(remainDto.getInvest_creditor_amount_90d() == null ? 0.00 : remainDto.getInvest_creditor_amount_90d());
      //16.30内债权转让申请次数
      model.setCreditor_transfer_apply_times_30d(remainDto.getCreditor_transfer_apply_times_30d() == null ? 0 : remainDto.getCreditor_transfer_apply_times_30d());
      //17.60内债权转让申请次数
      model.setCreditor_transfer_apply_times_60d(remainDto.getCreditor_transfer_apply_times_60d() == null ? 0 : remainDto.getCreditor_transfer_apply_times_60d());
      //18.90内债权转让申请次数
      model.setCreditor_transfer_apply_times_90d(remainDto.getCreditor_transfer_apply_times_90d() == null ? 0 : remainDto.getCreditor_transfer_apply_times_90d());
      //19.30内债权转让成功次数
      model.setCreditor_transfer_success_times_30d(remainDto.getCreditor_transfer_success_times_30d() == null ? 0 : remainDto.getCreditor_transfer_success_times_30d());
      //20.60内债权转让成功次数
      model.setCreditor_transfer_success_times_60d(remainDto.getCreditor_transfer_success_times_60d() == null ? 0 : remainDto.getCreditor_transfer_success_times_60d());
      //21.90内债权转让成功次数
      model.setCreditor_transfer_success_times_90d(remainDto.getCreditor_transfer_success_times_90d() == null ? 0 : remainDto.getCreditor_transfer_success_times_90d());
      //22.最后一次投资的时间
      model.setLatest_invest_time(remainDto.getLatest_invest_time() == null ? 0 : remainDto.getLatest_invest_time());
      //23.30内债权转让失败次数
      model.setCreditor_transfer_failed_times_30d(remainDto.getCreditor_transfer_failed_times_30d() == null ? 0 : remainDto.getCreditor_transfer_failed_times_30d());
      //24.60内债权转让失败次数
      model.setCreditor_transfer_failed_times_60d(remainDto.getCreditor_transfer_failed_times_60d() == null ? 0 : remainDto.getCreditor_transfer_failed_times_60d());
      //25.90内债权转让失败次数
      model.setCreditor_transfer_failed_times_90d(remainDto.getCreditor_transfer_failed_times_90d() == null ? 0 : remainDto.getCreditor_transfer_failed_times_90d());
      //26.最近登录时间
      model.setLatest_login_time(remainDto.getLatest_login_time() == null ? 0 : remainDto.getLatest_login_time());
      //27.最近登录的渠道
      model.setChannel(remainDto.getChannel() == null ? 0 : remainDto.getChannel());
      //未投资天数
      Long interval = (FrameUtil.getTime()-remainDto.getRegist_time())/INTERVAL_1DAY_SECONDS;
      if(model.getLatest_invest_time() != null && model.getLatest_invest_time().longValue() > 0){
        interval = (FrameUtil.getTime()-model.getLatest_invest_time())/INTERVAL_1DAY_SECONDS;
      }
      model.setNo_invest_days(Integer.valueOf(interval.toString()));
      //23.最近使用的投资券
      UserTicketUsedDto ticketUsedDto = userService.queryUserTicketsUsedRecentlyById(user_id);
      model.setLatest_used_volumn(ticketUsedDto==null? "":ticketUsedDto.getInfoDescription());
      //24.在投金额
      model.setInvesting_amount(remainDto.getInvesting_amount() == null ? 0.00 : remainDto.getInvesting_amount());
      //25.留存状态
      if (remainDto.getRegist_time() != null && remainDto.getRegist_time() > 0){
        boolean before20170101 = remainDto.getRegist_time() < TIME_STAMP_20170101;
        boolean less365Day = (FrameUtil.getTime() - remainDto.getRegist_time())/INTERVAL_1DAY_SECONDS <= 365;
        if (before20170101 && model.getInvesting_amount() > 0) {
          model.setKeep_status(KeepStatus.PERM_USER.getCode());
        }
        else if (model.getAll_invest_times() > 3
          && model.getInvesting_amount() > 0 && !before20170101) {
          model.setKeep_status(KeepStatus.OLD_USER.getCode());
        }
        else if (model.getAll_invest_times() <= 3 && model.getAll_invest_times() > 1
          && model.getInvesting_amount() > 0 && less365Day){
          model.setKeep_status(KeepStatus.EDEN_USER.getCode());
        }else {
          model.setKeep_status(KeepStatus.OTHERS.getCode());
        }
      }

      //26.分享后成功注册人数
      model.setShared_users(remainDto.getShared_users() == null ? 0 : remainDto.getShared_users());

      //更新用户状态
      if(model.getAll_invest_times().intValue()==1){
        model.setUser_status(UserStatus.INVESTED.getCode());
        model.setTransfer_status(TransferStatus.INVESTED.getCode());
      }
      //如果用户已复投，说明不属于4种转换状态中的任一种
      if (model.getAll_invest_times()>1){
        model.setTransfer_status(TransferStatus.OTHERS.getCode());
      }
      if(model.getAll_invest_times().intValue() > 1 && model.getShared_users().intValue() == 0){
        model.setUser_status(UserStatus.REINVEST.getCode());
      }
      if(model.getAll_invest_times().intValue() > 1 && model.getShared_users().intValue() > 0){
        model.setUser_status(UserStatus.SHARED.getCode());
      }
      //设置推广状态
      if (model.getShared_users() == 0) {
        model.setShare_status(ShareStatus.UN_SHARED.getCode());
      } else if(model.getShared_users() > 0 && model.getShared_users() <= 5) {
        model.setShare_status(ShareStatus.NEW_SHARED.getCode());
      } else if (model.getShared_users() > 5 && model.getShared_users() <= 10) {
        model.setShare_status(ShareStatus.NOR_SHARED.getCode());
      } else {
        model.setShare_status(ShareStatus.PRO_SHARED.getCode());
      }

      userGrowingStatisticsService.update(model);
    }
  }

  /**
   * 流失监控
   * @param user_id
   */
  private void recordLoss(long user_id) throws Exception {

    //1.未投资天数(已在留存监控中统计)
    //2.当前账户余额 （baseInfo已经统计）
    //3.在投项目个数==持有债权数(已在留存监控中统计)
    //4.最后一笔回款时间（baseInfo已经统计）

    //5.最后一次提现时间和金额
    CashDcsOrderModel cm = cashDcsOrderService.getModelOne(FrameUtil.newHashMap(
      "user_id", user_id,
      "status", 3,
      "sort", "addtime desc"
    ), DbWREnums.READ);
    if(cm != null){
      UserGrowingStatisticsModel model = new UserGrowingStatisticsModel();
      model.setUser_id(user_id);
      model.setLatest_cashout_amount(cm.getPrice());
      model.setLatest_cashout_time(cm.getAddtime());
      userGrowingStatisticsService.update(model);
    }

    //6.流失状态（baseInfo已经统计）

  }

}
